package com.liam.chinesevietnamesecorpus.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.liam.chinesevietnamesecorpus.common.exception.ServiceException;
import com.liam.chinesevietnamesecorpus.dto.BatchUploadResultDTO;
import com.liam.chinesevietnamesecorpus.dto.CorpusItemDTO;
import com.liam.chinesevietnamesecorpus.dto.CorpusItemUpdateDTO;
import com.liam.chinesevietnamesecorpus.entity.CorpusItem;
import com.liam.chinesevietnamesecorpus.entity.CorpusLibrary;
import com.liam.chinesevietnamesecorpus.mapper.CorpusItemMapper;
import com.liam.chinesevietnamesecorpus.mapper.CorpusLibraryMapper;
import com.liam.chinesevietnamesecorpus.service.CorpusItemService;
import com.liam.chinesevietnamesecorpus.vo.CorpusItemVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 语料服务实现类
 * 
 * @author Liam
 */
@Slf4j
@Service
public class CorpusItemServiceImpl implements CorpusItemService {

    @Autowired
    private CorpusItemMapper corpusItemMapper;

    @Autowired
    private CorpusLibraryMapper corpusLibraryMapper;

    @Override
    @Transactional
    public CorpusItemVO createCorpusItem(CorpusItemDTO corpusItemDTO) {
        // 检查语料库是否存在
        CorpusLibrary corpusLibrary = corpusLibraryMapper.selectById(corpusItemDTO.getLibraryId());
        if (corpusLibrary == null || "deleted".equals(corpusLibrary.getStatus())) {
            throw new ServiceException("语料库不存在");
        }

        // 创建语料对象
        CorpusItem corpusItem = BeanUtil.copyProperties(corpusItemDTO, CorpusItem.class);

        // 保存语料
        int result = corpusItemMapper.insert(corpusItem);
        if (result <= 0) {
            throw new ServiceException("创建语料失败");
        }

        log.info("语料创建成功：语料库ID={}", corpusItem.getLibraryId());

        // 转换为VO对象
        CorpusItemVO corpusItemVO = BeanUtil.copyProperties(corpusItem, CorpusItemVO.class);
        corpusItemVO.setLibraryName(corpusLibrary.getName());
        return corpusItemVO;
    }

    @Override
    public CorpusItemVO getCorpusItemById(Long id) {
        CorpusItem corpusItem = corpusItemMapper.selectById(id);
        if (corpusItem == null || "deleted".equals(corpusItem.getStatus())) {
            throw new ServiceException("语料不存在");
        }

        // 获取语料库信息
        CorpusLibrary corpusLibrary = corpusLibraryMapper.selectById(corpusItem.getLibraryId());
        String libraryName = corpusLibrary != null ? corpusLibrary.getName() : "未知语料库";

        // 转换为VO对象
        CorpusItemVO corpusItemVO = BeanUtil.copyProperties(corpusItem, CorpusItemVO.class);
        corpusItemVO.setLibraryName(libraryName);
        return corpusItemVO;
    }

    @Override
    @Transactional
    public CorpusItemVO updateCorpusItem(Long id, CorpusItemUpdateDTO corpusItemUpdateDTO) {
        // 查询语料是否存在
        CorpusItem existingItem = corpusItemMapper.selectById(id);
        if (existingItem == null || "deleted".equals(existingItem.getStatus())) {
            throw new ServiceException("语料不存在");
        }

        // 更新语料信息
        CorpusItem corpusItem = new CorpusItem();
        corpusItem.setId(id);
        BeanUtil.copyProperties(corpusItemUpdateDTO, corpusItem);

        int result = corpusItemMapper.updateById(corpusItem);
        if (result <= 0) {
            throw new ServiceException("更新失败");
        }

        log.info("语料信息更新成功：语料ID={}", id);

        // 返回更新后的语料信息
        return getCorpusItemById(id);
    }

    @Override
    @Transactional
    public void deleteCorpusItem(Long id) {
        // 查询语料是否存在
        CorpusItem corpusItem = corpusItemMapper.selectById(id);
        if (corpusItem == null || "deleted".equals(corpusItem.getStatus())) {
            throw new ServiceException("语料不存在");
        }

        // 软删除：更新状态为deleted
        CorpusItem deleteItem = new CorpusItem();
        deleteItem.setId(id);
        deleteItem.setStatus("deleted");

        int result = corpusItemMapper.updateById(deleteItem);
        if (result <= 0) {
            throw new ServiceException("删除失败");
        }

        log.info("语料删除成功：语料ID={}", id);
    }

    @Override
    public IPage<CorpusItemVO> getCorpusItemList(int page, int size, Long libraryId, String keyword, String sourceText, String targetText) {
        // 创建分页对象
        Page<CorpusItem> itemPage = new Page<>(page, size);

        // 构建查询条件
        LambdaQueryWrapper<CorpusItem> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ne(CorpusItem::getStatus, "deleted");
        
        if (libraryId != null) {
            queryWrapper.eq(CorpusItem::getLibraryId, libraryId);
        }
        
        // 平行语料精确搜索：同时匹配源语言和目标语言
        if (StringUtils.hasText(sourceText) && StringUtils.hasText(targetText)) {
            log.info("执行平行语料搜索：sourceText={}, targetText={}", sourceText, targetText);
            queryWrapper.and(wrapper -> wrapper
                .like(CorpusItem::getSourceText, sourceText)
                .like(CorpusItem::getTargetText, targetText)
            );
        }
        // 普通关键词搜索：在源语言或目标语言中搜索
        else if (StringUtils.hasText(keyword)) {
            log.info("执行普通关键词搜索：keyword={}", keyword);
            queryWrapper.and(wrapper -> wrapper
                .like(CorpusItem::getSourceText, keyword)
                .or()
                .like(CorpusItem::getTargetText, keyword)
            );
        }
        
        queryWrapper.orderByDesc(CorpusItem::getCreateTime);

        // 查询分页数据
        IPage<CorpusItem> itemIPage = corpusItemMapper.selectPage(itemPage, queryWrapper);

        // 转换为VO对象
        IPage<CorpusItemVO> itemVOPage = new Page<>(itemIPage.getCurrent(), itemIPage.getSize(), itemIPage.getTotal());
        itemVOPage.setRecords(
            itemIPage.getRecords().stream()
                .map(item -> {
                    CorpusItemVO itemVO = BeanUtil.copyProperties(item, CorpusItemVO.class);
                    // 获取语料库名称
                    CorpusLibrary corpusLibrary = corpusLibraryMapper.selectById(item.getLibraryId());
                    itemVO.setLibraryName(corpusLibrary != null ? corpusLibrary.getName() : "未知语料库");
                    return itemVO;
                })
                .toList()
        );

        return itemVOPage;
    }

    @Override
    @Transactional
    public BatchUploadResultDTO batchUploadCorpusItems(MultipartFile file, Long libraryId, Boolean hasIndexColumn) {
        // 验证语料库是否存在
        CorpusLibrary corpusLibrary = corpusLibraryMapper.selectById(libraryId);
        if (corpusLibrary == null || "deleted".equals(corpusLibrary.getStatus())) {
            throw new ServiceException("语料库不存在");
        }

        // 验证文件
        if (file.isEmpty()) {
            throw new ServiceException("文件不能为空");
        }

        String fileName = file.getOriginalFilename();
        if (fileName == null || (!fileName.endsWith(".xlsx") && !fileName.endsWith(".xls"))) {
            throw new ServiceException("文件格式不正确，请上传Excel文件");
        }

        BatchUploadResultDTO result = new BatchUploadResultDTO();
        List<String> errorMessages = new ArrayList<>();

        try {
            // 创建工作簿
            Workbook workbook = createWorkbook(file);
            
            // 获取第一个工作表
            Sheet sheet = workbook.getSheetAt(0);
            
            // 获取数据行数
            int lastRowNum = sheet.getLastRowNum();
            if (lastRowNum < 1) {
                throw new ServiceException("Excel文件中没有数据");
            }

            log.info("开始处理Excel文件，共{}行数据", lastRowNum);

            // 批量处理数据
            List<CorpusItem> itemsToInsert = new ArrayList<>();
            
            // 从第二行开始读取数据（跳过表头）
            for (int i = 1; i <= lastRowNum; i++) {
                Row row = sheet.getRow(i);
                if (row == null) {
                    continue;
                }

                try {
                    CorpusItem item = parseRowToCorpusItem(row, libraryId, hasIndexColumn, i);
                    if (item != null) {
                        itemsToInsert.add(item);
                    }
                } catch (Exception e) {
                    result.setFailCount(result.getFailCount() + 1);
                    errorMessages.add(String.format("第%d行数据错误：%s", i + 1, e.getMessage()));
                    log.warn("第{}行数据解析失败：{}", i + 1, e.getMessage());
                }
                
                result.setTotalCount(result.getTotalCount() + 1);
            }

            // 批量插入数据
            if (!itemsToInsert.isEmpty()) {
                for (CorpusItem item : itemsToInsert) {
                    try {
                        corpusItemMapper.insert(item);
                        result.setSuccessCount(result.getSuccessCount() + 1);
                    } catch (Exception e) {
                        result.setFailCount(result.getFailCount() + 1);
                        errorMessages.add(String.format("保存语料失败：%s", e.getMessage()));
                        log.error("保存语料失败：{}", e.getMessage(), e);
                    }
                }
            }

            workbook.close();

            // 设置错误信息
            if (!errorMessages.isEmpty()) {
                result.setErrorMessage(String.join("; ", errorMessages));
            }

            log.info("批量上传完成：成功{}条，失败{}条", result.getSuccessCount(), result.getFailCount());
            return result;

        } catch (IOException e) {
            log.error("读取Excel文件失败：{}", e.getMessage(), e);
            throw new ServiceException("读取Excel文件失败：" + e.getMessage());
        } catch (Exception e) {
            log.error("批量上传处理失败：{}", e.getMessage(), e);
            throw new ServiceException("批量上传处理失败：" + e.getMessage());
        }
    }

    /**
     * 创建工作簿
     */
    private Workbook createWorkbook(MultipartFile file) throws IOException {
        String fileName = file.getOriginalFilename();
        if (fileName != null && fileName.endsWith(".xlsx")) {
            return new XSSFWorkbook(file.getInputStream());
        } else {
            return new HSSFWorkbook(file.getInputStream());
        }
    }

    /**
     * 解析行数据为语料对象
     */
    private CorpusItem parseRowToCorpusItem(Row row, Long libraryId, Boolean hasIndexColumn, int rowIndex) {
        String sourceText;
        String targetText;

        if (hasIndexColumn) {
            // 三列格式：序号、中文原文、越南语译文
            if (row.getLastCellNum() < 3) {
                throw new ServiceException("数据格式错误，应包含3列：序号、中文原文、越南语译文");
            }
            sourceText = getCellStringValue(row.getCell(1));
            targetText = getCellStringValue(row.getCell(2));
        } else {
            // 两列格式：中文原文、越南语译文
            if (row.getLastCellNum() < 2) {
                throw new ServiceException("数据格式错误，应包含2列：中文原文、越南语译文");
            }
            sourceText = getCellStringValue(row.getCell(0));
            targetText = getCellStringValue(row.getCell(1));
        }

        // 验证数据
        if (!StringUtils.hasText(sourceText)) {
            throw new ServiceException("中文原文不能为空");
        }
        if (!StringUtils.hasText(targetText)) {
            throw new ServiceException("越南语译文不能为空");
        }

        // 创建语料对象
        CorpusItem item = new CorpusItem();
        item.setLibraryId(libraryId);
        item.setSourceText(sourceText.trim());
        item.setTargetText(targetText.trim());
        item.setStatus("active");

        return item;
    }

    /**
     * 获取单元格字符串值
     */
    private String getCellStringValue(Cell cell) {
        if (cell == null) {
            return "";
        }

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();
            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getDateCellValue().toString();
                } else {
                    // 避免科学计数法
                    double numericValue = cell.getNumericCellValue();
                    if (numericValue == (long) numericValue) {
                        return String.valueOf((long) numericValue);
                    } else {
                        return String.valueOf(numericValue);
                    }
                }
            case BOOLEAN:
                return String.valueOf(cell.getBooleanCellValue());
            case FORMULA:
                return cell.getCellFormula();
            default:
                return "";
        }
    }
}
